namespace Test.Robotics.Runtime
{
    using System;
    using System.Drawing;
    using System.IO;
    using System.Reflection;
    using System.Runtime.Serialization;
    using System.Threading;
    using Microsoft.Robotics.Numerics;
    using Microsoft.Robotics.Runtime;
    using Microsoft.Robotics.Vision;
    using Microsoft.Robotics.Vision.Cameras;
    using Microsoft.Robotics.Vision.Runtime.Cameras;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Test.Robotics.Runtime;

    /// <summary>
    /// Validates Kinect frame down scaling utility
    /// </summary>
    [TestClass]
    public class KinectFrameDownscalerTests
    {        
        /// <summary>
        /// Tests if down scaling works when scaling factor is greater than 1
        /// </summary>
        [Priority(0)]
        [TestMethod]
        [TestCategory("Unit")]
        public void DownscalerTransformsImageSize()
        {            
            Tuple<short[], Size> original = this.GenerateBogusDepthFrame<short>(100, 200);

            int downScaleFactor = 2;

            Tuple<short[], Size> transformed = ImageOperations2D.Downscale<short>(original.Item1, original.Item2, downScaleFactor);

            Assert.AreEqual(100 * 200 / (downScaleFactor * downScaleFactor), transformed.Item1.Length);
            Assert.AreEqual(100 / downScaleFactor, transformed.Item2.Width);
            Assert.AreEqual(200 / downScaleFactor, transformed.Item2.Height);
        }

        /// <summary>
        /// Tests if DataIsPreservedDuringScaling
        /// </summary>
        [Priority(0)]
        [TestMethod]
        [TestCategory("Unit")]
        public void DataIsPreservedDuringScaling()
        {
            int scalingFactor = 2;
            int width = 200;
            int height = 100;

            Tuple<int[], Size> original = this.GenerateBogusDepthFrame<int>(width, height);

            // Initialize original array with some unique data
            for (int i = 0; i < original.Item1.Length; ++i)
            {
                original.Item1[i] = i;
            }

            // Transform
            Tuple<int[], Size> transformed = ImageOperations2D.Downscale<int>(original.Item1, original.Item2, scalingFactor);

            // Now check to see if its being decimated properly (by skipping rows and columns)
            for (int i = 0; i < height / scalingFactor; ++i)
            {
                int rowInOriginal = i * width / scalingFactor;

                for (int j = 0; j < width / scalingFactor; ++j)
                {
                    int indexInTransformed = rowInOriginal + j;

                    int expected = i * scalingFactor * width + j * scalingFactor;

                    Assert.AreEqual(expected, transformed.Item1[indexInTransformed]);
                }
            }
        }

        /// <summary>
        /// Helper method to generate bogus depth frame
        /// </summary>
        /// <typeparam name="T">Type of pixel</typeparam>
        /// <param name="width">Frame width</param>
        /// <param name="height">Frame height</param>
        /// <returns>New empty image frame</returns>        
        private Tuple<T[], Size> GenerateBogusDepthFrame<T>(int width, int height) 
        {
            T[] frame = new T[width * height];

            return new Tuple<T[], Size>(frame, new Size(width, height));
        }       
    }
}
